<!doctype html>
<html>

<head>
<title>Grant, Rollins, Burgess &raquo; COS 452 &mdash; Assignment 3</title> 
<meta http-equiv="content-type" content="text/html; charset=ISO-8859-1">

<script type="text/javascript" src="glMatrix-0.9.5.min.js"></script>
<script type="text/javascript" src="webgl-utils.js"></script>

<script id="shader-fs" type="x-shader/x-fragment">
        #ifdef GL_ES
        precision highp float;
        #endif

        varying vec4 vColor;
        void main(void) {
                gl_FragColor = vColor;
        }
</script>

<script id="shader-vs" type="x-shader/x-vertex">
        attribute vec3 aVertexPosition;
        attribute vec4 aVertexColor;
 
        uniform mat4 uMVMatrix;
        uniform mat4 uPMatrix;
 
        varying vec4 vColor;
        void main(void) {
                gl_Position = uPMatrix * uMVMatrix * vec4(aVertexPosition, 1.0);
                vColor = aVertexColor;
        }
</script>


<script type="text/javascript">
        var gl;

        function initGL(canvas) {
                try {
                        gl = canvas.getContext("experimental-webgl");
                        gl.viewportWidth = canvas.width;
                        gl.viewportHeight = canvas.height;
                } catch (e) {}
                if (!gl) 
                        alert("Could not initialise WebGL, sorry :-(");
        }

        function getShader(gl, id) {
                var shaderScript = document.getElementById(id);
                if (!shaderScript)
                        return null;

                var str = "";
                var k = shaderScript.firstChild;
                while (k) {
                        if (k.nodeType == 3)
                                str += k.textContent;
                        k = k.nextSibling;
                } // while

                var shader;
                if (shaderScript.type == "x-shader/x-fragment") {
                        shader = gl.createShader(gl.FRAGMENT_SHADER);
                } else if (shaderScript.type == "x-shader/x-vertex") {
                        shader = gl.createShader(gl.VERTEX_SHADER);
                } else {
                        return null;
                }

                gl.shaderSource(shader, str);
                gl.compileShader(shader);

                if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {
                        alert(gl.getShaderInfoLog(shader));
                        return null;
                }

                return shader;
        }

        var shaderProgram;

        function initShaders() {
                var fragmentShader = getShader(gl, "shader-fs");
                var vertexShader = getShader(gl, "shader-vs");

                shaderProgram = gl.createProgram();
                gl.attachShader(shaderProgram, vertexShader);
                gl.attachShader(shaderProgram, fragmentShader);
                gl.linkProgram(shaderProgram);

                if (!gl.getProgramParameter(shaderProgram, gl.LINK_STATUS)) {
                        alert("Could not initialise shaders");
                }

                gl.useProgram(shaderProgram);

                shaderProgram.vertexPositionAttribute = gl.getAttribLocation(shaderProgram, "aVertexPosition");
                gl.enableVertexAttribArray(shaderProgram.vertexPositionAttribute);
 
                shaderProgram.vertexColorAttribute = gl.getAttribLocation(shaderProgram, "aVertexColor");
                gl.enableVertexAttribArray(shaderProgram.vertexColorAttribute);
	
                shaderProgram.pMatrixUniform = gl.getUniformLocation(shaderProgram, "uPMatrix");
                shaderProgram.mvMatrixUniform = gl.getUniformLocation(shaderProgram, "uMVMatrix");
        }

        var mvMatrix = mat4.create();
        var mvMatrixStack = [];
        var pMatrix = mat4.create();

        function mvMatrixPush() {
                var copy = mat4.create();
                mat4.set(mvMatrix, copy);
                mvMatrixStack.push(copy);
        }

        function mvMatrixPop() {
                if (mvMatrixStack.length == 0) 
                        throw "Invalid popMatrix!";
                mvMatrix = mvMatrixStack.pop();
        }
    
        function setMatrixUniforms() {
                gl.uniformMatrix4fv(shaderProgram.pMatrixUniform, false, pMatrix);
                gl.uniformMatrix4fv(shaderProgram.mvMatrixUniform, false, mvMatrix);
        }

        function degToRad(degrees) {
                return degrees * Math.PI / 180;
        }


	var currentlyPressedKeys = {};

	function handleKeyDown(event) {
        	currentlyPressedKeys[event.keyCode] = true;
	}

	function handleKeyUp(event) {
		currentlyPressedKeys[event.keyCode] = false;
	}

	var pitch = 0;
	var pitchRate = 0;

	var yaw = 0;
	var yawRate = 0;

	var xPos = 0;
	var yPos = 0.4;
	var zPos = 0;

	var speed = 0;
	
	var echo = 0;

	function handleKeys() {
		echo = 0;
		if (currentlyPressedKeys[69]) {
			echo = 1;
		}
		
		if (currentlyPressedKeys[33]) {
			// Page Up
			pitchRate = 0.1;
		} else if (currentlyPressedKeys[34]) {
			// Page Down
			pitchRate = -0.1;
		} else {
			pitchRate = 0;
		}

		if (currentlyPressedKeys[37]) {
			// Left cursor key
			yawRate = 0.1;
		} else if (currentlyPressedKeys[39]) {
			// Right cursor key
			yawRate = -0.1;
		} else {
			yawRate = 0;
		}

		if (currentlyPressedKeys[38]) {
			// Up cursor key
			speed = 0.003;
		} else if (currentlyPressedKeys[40]) {
			// Down cursor key
			speed = -0.003;
		} else {
			speed = 0;
		}
	}


	var worldVertexPositionBuffer = null;
	var worldVertexColorBuffer = null;
	var worldVertexPositionBoundary;
	
	function handleRoom(data) {
		worldVertexPositionBuffer = gl.createBuffer();
		gl.bindBuffer(gl.ARRAY_BUFFER, worldVertexPositionBuffer);
		gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(data.room.vertexPositions), gl.STATIC_DRAW);
		worldVertexPositionBuffer.itemSize = data.room.positionItemSize;
		worldVertexPositionBuffer.numItems = data.room.positionNumItems;
		
		worldVertexPositionBoundary = data.room.positionBoundary;
		
		worldVertexColorBuffer = gl.createBuffer();
		gl.bindBuffer(gl.ARRAY_BUFFER, worldVertexColorBuffer);
		gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(data.room.vertexColors), gl.STATIC_DRAW);
		worldVertexColorBuffer.itemSize = data.room.colorItemSize;
		worldVertexColorBuffer.numItems = data.room.colorNumItems;
	}

	function handleEricsModels(data) {
	}
	
	function handleEricasModels(data) {
	}
	
	function handleAlexsModels(data) {
		var models = data.alex;
		// place cube
		// place wall sconce
	}
	
	function loadWorld() {
		var request = new XMLHttpRequest();
		request.open("GET", "world.json");
		request.onreadystatechange = function () {
			if (request.readyState == 4) {
				data = JSON.parse(request.responseText);
				handleRoom(data);
				handleEricsModels(data);
				handleEricasModels(data);
				handleAlexsModels(data);
				document.getElementById("loadingtext").textContent = "";
			}
		}
		request.send();
	}

	function drawScene() {
		gl.viewport(0, 0, gl.viewportWidth, gl.viewportHeight);
		gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);

		if (worldVertexColorBuffer == null || worldVertexPositionBuffer == null) {
			return;
		}

		mat4.perspective(45, gl.viewportWidth / gl.viewportHeight, 0.1, 100.0, pMatrix);

		mat4.identity(mvMatrix);

		mat4.rotate(mvMatrix, degToRad(-pitch), [1, 0, 0]);
		mat4.rotate(mvMatrix, degToRad(-yaw), [0, 1, 0]);
		mat4.translate(mvMatrix, [-xPos, -yPos, -zPos]);
				
		gl.bindBuffer(gl.ARRAY_BUFFER, worldVertexColorBuffer);

		gl.vertexAttribPointer(shaderProgram.vertexColorAttribute, worldVertexColorBuffer.itemSize, gl.FLOAT, false, 0, 0);

		gl.bindBuffer(gl.ARRAY_BUFFER, worldVertexPositionBuffer);
		gl.vertexAttribPointer(shaderProgram.vertexPositionAttribute, worldVertexPositionBuffer.itemSize, gl.FLOAT, false, 0, 0);

		setMatrixUniforms();
		gl.drawArrays(gl.TRIANGLES, 0, worldVertexPositionBuffer.numItems);
	}


	var lastTime = 0;
	// Used to make us "jog" up and down as we move forward.
	var joggingAngle = 0;

	function animate() {
		var timeNow = new Date().getTime();
		if (lastTime != 0) {
			var elapsed = timeNow - lastTime;

			if (speed != 0) {
				var xProposed = xPos - Math.sin(degToRad(yaw)) * speed * elapsed;
				var zProposed = zPos - Math.cos(degToRad(yaw)) * speed * elapsed;
				
				//if (echo) { debug("xProposed="+Math.abs(xProposed)); }
				if (Math.abs(xProposed) <= worldVertexPositionBoundary)
					xPos = xProposed;
				if (Math.abs(zProposed) <= worldVertexPositionBoundary)
					zPos = zProposed;
				
				joggingAngle += elapsed * 0.6; 
				yPos = Math.sin(degToRad(joggingAngle)) / 20 + 0.4
			}

			yaw += yawRate * elapsed;
			pitch += pitchRate * elapsed;

		}
		lastTime = timeNow;
	}

	function tick() {
		requestAnimFrame(tick);
		handleKeys();
		drawScene();
		animate();
	}

	function debug(string) {
		document.getElementById("echoOutput").textContent = string;
	}

	function webGLStart() {
		var canvas = document.getElementById("assignment3-canvas");
		initGL(canvas);
		initShaders();
		loadWorld();

		gl.clearColor(0.0, 0.0, 0.0, 1.0);
		gl.enable(gl.DEPTH_TEST);

		document.onkeydown = handleKeyDown;
		document.onkeyup = handleKeyUp;
		
		tick();
	}

</script>
</head>
<body onload="webGLStart();">

	<div>
		<span id="loadingtext">world loading...</span>
	</div>

	<div>
		<canvas id="assignment3-canvas" style="border: none;" width="500" height="500"></canvas>
	</div>

	<h2>Controls:</h2>
	<ul>		
                <li><span>Arrow keys Up/Down <strong>move</strong> Forward, Backward</span></li>
		<li><span>Arrow keys Left/Right <strong>rotate</strong> Left, Right</span></li>
                <li><span>Page Up/Down <strong>look</strong> Up, Down</span></li>
		<li><span>'e' <strong>Echo</strong> conditional debug string; usage: if (echo) debug(string);</span></li>
	</ul>
	
	<h2>Debug:</h2>
	<div><span id="echoOutput">no debug output</span></div>
</body>

</html>
